/* File: ast_expr.cc
 * -----------------
 * Implementation of expression node classes.
 */

#include <string.h>
#include "ast_expr.h"
#include "ast_type.h"
#include "ast_decl.h"
#include "codegen.h"
#include "errors.h"
#include "tac.h"

Decl* Expr::getField(Identifier *f, Node *n) {
        while (n != NULL) {
                Decl *d = n->getScope()->map->Lookup(f->getName());
                if ( d != NULL ){
                        return d;
                }
                n = n->GetParent();
        }
        return NULL;
}

Decl* Expr::getField(Identifier *f, Type *t) {
        while ( t != NULL ) {
                Decl *td = Program::globalScope->map->Lookup(t->getName());
                Decl *d = td->getScope()->map->Lookup(f->getName());
                if ( d != NULL ) {
                        return d;
                }
                if ( dynamic_cast<ClassDecl*>(td) ) {
                        t = static_cast<ClassDecl*>(td)->getExtends();
                } else {
                        break;
                }
        }
        return NULL;
}

Decl* Expr::getField(Identifier *f, Expr *e) {
        if ( e != NULL ) {
                return getField(f,e->getType());
        }
        Decl *d = getField(f,static_cast<Node*>(this));
        if ( d == NULL ){
                ClassDecl *classDecl = getClassDecl();
                if ( classDecl != NULL ) {
                        d = getField(f, classDecl->getType());
                }
        }
        return d;
}

Location *Expr::getLoc() {
        return new Location(fpRelative, CodeGenerator::OffsetToFirstParam, "this");
}

ClassDecl *Expr::getClassDecl() {
        Node *node = this;
        while ( node != NULL ) {
                if ( dynamic_cast<ClassDecl*>(node) ) {
                        return static_cast<ClassDecl*>(node);
                }
                node = node->GetParent();
        }
        return NULL;
}

IntConstant::IntConstant(yyltype loc, int val) : Expr(loc) {
    value = val;
}

int IntConstant::getSpace() {
        return 4;
}

Location *IntConstant::codeGen(CodeGenerator *gen) {
        return gen->GenLoadConstant(value);
}

Type *IntConstant::getType() {
        return Type::intType;
}

DoubleConstant::DoubleConstant(yyltype loc, double val) : Expr(loc) {
    value = val;
}

int DoubleConstant::getSpace() {
        return 4;
}

Location *DoubleConstant::codeGen(CodeGenerator *gen) {
        return NULL;
}

Type *DoubleConstant::getType() {
        return Type::doubleType;
}

BoolConstant::BoolConstant(yyltype loc, bool val) : Expr(loc) {
    value = val;
}

int BoolConstant::getSpace() {
        return 4;
}

Location *BoolConstant::codeGen(CodeGenerator *gen) {
        return gen->GenLoadConstant(value ? 1 : 0);
}

Type *BoolConstant::getType() {
        return Type::boolType;
}

StringConstant::StringConstant(yyltype loc, const char *val) : Expr(loc) {
    Assert(val != NULL);
    value = strdup(val);
}

int StringConstant::getSpace() {
        return 4;
}

Location *StringConstant::codeGen(CodeGenerator *gen) {
        return gen->GenLoadConstant(value);
}

Type *StringConstant::getType() {
        return Type::stringType;
}

int NullConstant::getSpace() {
        return 4;
}

Location *NullConstant::codeGen(CodeGenerator *gen) {
        return gen->GenLoadConstant(0);
}

Type *NullConstant::getType() {
        return Type::nullType;
}

Operator::Operator(yyltype loc, const char *tok) : Node(loc) {
    Assert(tok != NULL);
    strncpy(tokenString, tok, sizeof(tokenString));
}
CompoundExpr::CompoundExpr(Expr *l, Operator *o, Expr *r) 
  : Expr(Join(l->GetLocation(), r->GetLocation())) {
    Assert(l != NULL && o != NULL && r != NULL);
    (op=o)->SetParent(this);
    (left=l)->SetParent(this); 
    (right=r)->SetParent(this);
}

CompoundExpr::CompoundExpr(Operator *o, Expr *r) 
  : Expr(Join(o->GetLocation(), r->GetLocation())) {
    Assert(o != NULL && r != NULL);
    left = NULL; 
    (op=o)->SetParent(this);
    (right=r)->SetParent(this);
}
   
  
ArrayAccess::ArrayAccess(yyltype loc, Expr *b, Expr *s) : LValue(loc) {
    (base=b)->SetParent(this); 
    (subscript=s)->SetParent(this);
}

int ArrayAccess::getSpace() {
        return CodeGenerator::VarSize + getSpaceAddr();
}

int ArrayAccess::getSpaceStore() {
        return CodeGenerator::VarSize * getSpaceAddr();
}

int ArrayAccess::getSpaceAddr() {
        return getSpaceCheck() + subscript->getSpace() + CodeGenerator::VarSize * 4 + base->getSpace();
}

int ArrayAccess::getSpaceCheck() {
        return CodeGenerator::VarSize * 8;
}

Type *ArrayAccess::getType() {
        return base->getType();
}

Location *ArrayAccess::codeGen(CodeGenerator *gen) {
        return gen->GenLoad(codeGenAddr(gen));
}

Location *ArrayAccess::codeGenStore(CodeGenerator *gen, Location *l) {
        Location *add = codeGenAddr(gen);
        gen->GenStore(add, l);
        return gen->GenLoad(add);
}

Location *ArrayAccess::codeGenAddr(CodeGenerator *gen) {
        Location *sub = subscript->codeGen(gen);
        Location *bas = base->codeGen(gen);
        codeGenCheck(gen, bas, sub);
        Location *cons = gen->GenLoadConstant(CodeGenerator::VarSize);
        Location *times = gen->GenBinaryOp("*", sub, cons);
        Location *adder = gen->GenBinaryOp("+", times, cons);
        return gen->GenBinaryOp("+",bas,adder);
}

Location *ArrayAccess::codeGenCheck(CodeGenerator *gen, Location *l, Location *l2) {
        Location *z = gen->GenLoadConstant(0);
        Location *s = gen->GenLoad(l);
        Location *lz = gen->GenBinaryOp("<",l2,z);
        Location *gs = gen->GenBinaryOp("<",s,l2);
        Location *es = gen->GenBinaryOp("==",s,l2);
        Location *ges = gen->GenBinaryOp("||",gs,es);
        Location *geslz = gen->GenBinaryOp("||",ges,lz);
        const char *p = gen->NewLabel();
        gen->GenIfZ(geslz,p);
        gen->GenBuiltInCall(PrintString, gen->GenLoadConstant(err_arr_out_of_bounds));
        gen->GenBuiltInCall(Halt);
        gen->GenLabel(p);
        return NULL;
}
     
FieldAccess::FieldAccess(Expr *b, Identifier *f) 
  : LValue(b? Join(b->GetLocation(), f->GetLocation()) : *f->GetLocation()) {
    Assert(f != NULL); // b can be be NULL (just means no explicit base)
    base = b; 
    if (base) base->SetParent(this); 
    (field=f)->SetParent(this);
}

int FieldAccess::getSpace() {
        FieldAccess *b = dynamic_cast<FieldAccess*>(base);
        VarDecl *f = getDecl();
        Assert(f != NULL);
        if ( base != NULL ) {
                return getSpaceMemLoc(f);
        }
        return CodeGenerator::VarSize;
}

Type *FieldAccess::getType() {
        VarDecl *d = getDecl();
        Assert(d != NULL);
        return d->getType();
}

Location *FieldAccess::codeGen(CodeGenerator *gen) {
        FieldAccess *b = dynamic_cast<FieldAccess*>(base);
        VarDecl *f = getDecl();
        Assert(f != NULL);
        if ( b == NULL ) {
                return codeGenMemLoc(gen, f);
        }
        VarDecl *bd = b->getDecl();
        Assert(bd != NULL);
        int o = f->getOffset();
        return gen->GenLoad(bd->getLocation(),o);
}

VarDecl *FieldAccess::getDecl() {
        Decl *d = getField(field,base);
        return dynamic_cast<VarDecl*>(d);
}

int FieldAccess::getSpaceMemLocStore(VarDecl *f) {
        return 0;
}

int FieldAccess::getSpaceStore() {
        FieldAccess *b = dynamic_cast<FieldAccess*>(base);
        VarDecl *f = getDecl();
        Assert(f != NULL);
        if ( b == NULL ) {
                return getSpaceMemLocStore(f);
        }
        return 0;
}

int FieldAccess::getSpaceMemLoc(VarDecl *f) {
        Location *loc = f->getLocation();
        if ( loc != NULL ) {
                return 0;
        }
        return CodeGenerator::VarSize;
}

Location *FieldAccess::codeGenMemLoc(CodeGenerator *gen, VarDecl *f) {
        Location *loc = f->getLocation();
        if (loc != NULL) {
                return loc;
        }
        Location *th = getLoc();
        return gen->GenLoad(th, f->getOffset());
}

Location *FieldAccess::codeGenMemLocStore(CodeGenerator *gen, Location *l, VarDecl *v) {
        Location *loc = v->getLocation();
        if ( loc != NULL ) {
                gen->GenAssign(loc,l);
                return loc;
        }
        Location *th = getLoc();
        gen->GenStore(th, l, v->getOffset());
        return th;
}

Location *FieldAccess::codeGenStore(CodeGenerator *gen, Location *l) {
        FieldAccess *b = dynamic_cast<FieldAccess*>(base);
        VarDecl *f = getDecl();
        Assert(f != NULL);
        if (b == NULL) {
                return codeGenMemLocStore(gen, l, f);
        }
        VarDecl *bd = b->getDecl();
        Assert(bd != NULL);
        int o = f->getOffset();
        Location *ltemp = bd->getLocation();
        gen->GenStore(ltemp, l, o);
        return ltemp;
}

Call::Call(yyltype loc, Expr *b, Identifier *f, List<Expr*> *a) : Expr(loc)  {
    Assert(f != NULL && a != NULL); // b can be be NULL (just means no explicit base)
    base = b;
    if (base) base->SetParent(this);
    (field=f)->SetParent(this);
    (actuals=a)->SetParentAll(this);
}
 
Location *Call::codeGen(CodeGenerator *gen) {
        if (isLengthCall()) {
                return codeGenArrayLength(gen);
        }
        return codeGenLabel(gen);
}

Location *Call::codeGenArrayLength(CodeGenerator *gen) {
        return gen->GenLoad(base->codeGen(gen));
}

int Call::getSpace() {
        if ( isLengthCall() ) {
                return getSpaceArrayLength();
        }
        getSpaceLabel();
        return getSpaceLabel();
}

bool Call::isLengthCall() {
        if ( base == NULL ) {
                return false;
        } else if ( dynamic_cast<ArrayType*>(base->getType()) == NULL) {
                return false;
        } else if ( strcmp("length", field->getName()) != 0 ) {
                return false;
        }
        return true;
}

FnDecl* Call::getDecl() {
        return dynamic_cast<FnDecl*>(getField(field,base));
}

Type *Call::getType() {
        if (isLengthCall()) {
                return Type::intType;
        }
        FnDecl *d = getDecl();
        Assert(d != NULL);
        return d->getType();
}

int Call::getSpaceDynamicDispatch() {
        return CodeGenerator::VarSize * 2;
}

Location *Call::codeGenLabel(CodeGenerator *gen) {
        List<Location*> *p = new List<Location*>;
        for ( int i = 0; i < actuals->NumElements(); i++ ) {
                p->Append(actuals->Nth(i)->codeGen(gen));
        }
        int n = p->NumElements();
        for ( int i = n - 1; i >= 0; i-- ) {
                gen->GenPushParam(p->Nth(i));
        }
        Location *returnVal;
        if ( !isMethodCall() ) {
                FnDecl *fnDecl = getDecl();
                returnVal = gen->GenLCall(fnDecl->getLabel(),fnDecl->checkReturn());
                gen->GenPopParams(n * CodeGenerator::VarSize);
        } else {
                Location *a;
                if ( base != NULL){
                        a = base->codeGen(gen);
                } else {
                        a = getLoc();
                }
                gen->GenPushParam(a);
                returnVal = codeGenDynamicDispatch(gen,a);
                gen->GenPopParams((n+1) * CodeGenerator::VarSize);
        }
        return returnVal;
}

int Call::getSpaceLabel() {
        int b = 0;
        for ( int i = 0; i < actuals->NumElements(); i++ ) {
                b = b + actuals->Nth(i)->getSpace();
        }
        if ( isMethodCall() ) {
                if ( base != NULL ) {
                        b = b + base->getSpace();
                }
                b = b + getSpaceDynamicDispatch();
        }
        getDecl();
        if ( getDecl()->checkReturn() ) {
                b = b + CodeGenerator::VarSize;
        }
        return b;
}

int Call::getSpaceArrayLength() {
        return CodeGenerator::VarSize + base->getSpace();
}

Location *Call::codeGenDynamicDispatch(CodeGenerator *gen, Location *b) {
        Location *v = gen->GenLoad(b);
        int o = getDecl()->getVOffset();
        Location *f = gen->GenLoad(v, o);
        return gen->GenACall(f, getDecl()->checkReturn());
}

bool Call::isMethodCall() {
        if ( base != NULL ) {
                return true;
        } else {
                ClassDecl *classDecl = getClassDecl();
                if ( classDecl == NULL ) {
                        return false;
                } else {
                        FnDecl *fnDecl = dynamic_cast<FnDecl*>(getField(field,classDecl->getType()));
                        if ( fnDecl == NULL ) {
                                return false;
                        } else {
                                return true;
                        }
                }
        }
}

NewExpr::NewExpr(yyltype loc, NamedType *c) : Expr(loc) { 
  Assert(c != NULL);
  (cType=c)->SetParent(this);
}

Location *NewExpr::codeGen(CodeGenerator *gen) {
        const char *n = cType->GetName();
        Decl *d = Program::globalScope->map->Lookup(n);
        Assert(d != NULL);
        Location *s = gen->GenLoadConstant(d->getSpace());
        Location *c = gen->GenLoadConstant(CodeGenerator::VarSize);
        Location *mem = gen->GenBuiltInCall(Alloc, gen->GenBinaryOp("+",c,s));
        gen->GenStore(mem, gen->GenLoadLabel(n));
        return mem;
}

Type *NewExpr::getType() {
        Decl *d = Program::globalScope->map->Lookup(cType->GetName());
        ClassDecl *c = dynamic_cast<ClassDecl*>(d);
        Assert(c != NULL);
        return c->getType();
}

int NewExpr::getSpace() {
        return CodeGenerator::VarSize * 5;
}

NewArrayExpr::NewArrayExpr(yyltype loc, Expr *sz, Type *et) : Expr(loc) {
    Assert(sz != NULL && et != NULL);
    (size=sz)->SetParent(this); 
    (elemType=et)->SetParent(this);
}

Location *NewArrayExpr::codeGen(CodeGenerator *gen) {
        Location *cons = gen->GenLoadConstant(CodeGenerator::VarSize);
        Location *s = size->codeGen(gen);
        codeGenCheck(gen,s);
        Location *op = gen->GenBinaryOp("*",s,cons);
        Location *mem = gen->GenBuiltInCall(Alloc, gen->GenBinaryOp("+",cons,op));
        gen->GenStore(mem,s);
        return mem;
}

Type *NewArrayExpr::getType() {
        return new ArrayType(elemType);
}

int NewArrayExpr::getSpace() {
        return size->getSpace() + getSpaceCheck() + CodeGenerator::VarSize * 4;
}

int NewArrayExpr::getSpaceCheck() {
        return CodeGenerator::VarSize * 5;
}

Location *NewArrayExpr::codeGenCheck(CodeGenerator *gen, Location *l) {
        Location *z = gen->GenLoadConstant(0);
        Location *lessZ = gen->GenBinaryOp("<", l, z);
        Location *equalZ = gen->GenBinaryOp("==", l, z);
        Location *lessEqualZ = gen->GenBinaryOp("||", lessZ, equalZ);
        const char *p = gen->NewLabel();
        gen->GenIfZ(lessEqualZ, p);
        gen->GenBuiltInCall(PrintString, gen->GenLoadConstant(err_arr_bad_size));
        gen->GenBuiltInCall(Halt);
        gen->GenLabel(p);
        return NULL;
}

Location *ReadLineExpr::codeGen(CodeGenerator *gen) {
        return gen->GenBuiltInCall(ReadLine);
}

Type *ReadLineExpr::getType() {
        return Type::stringType;
}
int ReadLineExpr::getSpace() {
        return CodeGenerator::VarSize;
}

int ReadIntegerExpr::getSpace() {
        return CodeGenerator::VarSize;
}

Location *ReadIntegerExpr::codeGen(CodeGenerator *gen) {
        return gen->GenBuiltInCall(ReadInteger);
}

Type *ReadIntegerExpr::getType() {
        return Type::intType;
}

int This::getSpace() {
        return 0;
}

Location *This::codeGen(CodeGenerator *gen) {
        return getLoc();
}

Type *This::getType() {
        ClassDecl *d = getClassDecl();
        Assert(d != NULL);
        return d->getType();
}

int AssignExpr::getSpace() {
        LValue *lv = dynamic_cast<LValue*>(left);
        if (lv != NULL) {
                return right->getSpace() + lv->getSpaceStore();
        }
        return left->getSpace() + right->getSpace();
}

Location *AssignExpr::codeGen(CodeGenerator *gen) {
        Location *rt = right->codeGen(gen);
        LValue *lv = dynamic_cast<LValue*>(left);
        if (lv != NULL) {
                return lv->codeGenStore(gen, rt);
        }
        Location *lt = left->codeGen(gen);
        gen->GenAssign(lt,rt);
        return lt;
}

Type *AssignExpr::getType() {
        return left->getType();
}

int LogicalExpr::getSpace() {
        const char *t = op->getTokenString();
        if ( strcmp("&&",t) == 0 ) { 
                return getSpaceAnd();
        } else if ( strcmp("||",t) == 0 ) {
                return getSpaceOr();
        } else if ( strcmp("!", t) == 0 ) {
                return getSpaceNot();
        }
        return 0;
}

int LogicalExpr::getSpaceAnd() {
        return CodeGenerator::VarSize + right->getSpace() + left->getSpace();
}

int LogicalExpr::getSpaceOr() {
        return CodeGenerator::VarSize + right->getSpace() + left->getSpace();
}

int LogicalExpr::getSpaceNot() {
        return CodeGenerator::VarSize * 3 + right->getSpace();
}

Location *LogicalExpr::codeGen(CodeGenerator *gen) {
        const char *t = op->getTokenString();
        if ( strcmp("&&",t) == 0 ) { 
                return codeGenAnd(gen);
        } else if ( strcmp("||",t) == 0 ) {
                return codeGenOr(gen);
        } else if ( strcmp("!", t) == 0 ) {
                return codeGenNot(gen);
        }
        return 0; 
}

Location *LogicalExpr::codeGenAnd(CodeGenerator *gen) {
        Location *lt = left->codeGen(gen);
        Location *rt = right->codeGen(gen);
        return gen->GenBinaryOp("&&",lt,rt);
}

Location *LogicalExpr::codeGenOr(CodeGenerator *gen) {
        Location *lt = left->codeGen(gen);
        Location *rt = right->codeGen(gen);
        return gen->GenBinaryOp("||",lt,rt);
}

Location *LogicalExpr::codeGenNot(CodeGenerator *gen) {
        const char* r0 = gen->NewLabel();
        const char* r1 = gen->NewLabel();
        Location *returnVal = gen->GenTempVar();
        Location *rt = right->codeGen(gen);
        gen->GenIfZ(rt, r1);
        gen->GenAssign(returnVal, gen->GenLoadConstant(0));
        gen->GenGoto(r0);
        gen->GenLabel(r1);
        gen->GenAssign(returnVal, gen->GenLoadConstant(1));
        gen->GenLabel(r0);
        return returnVal;
}

Type *LogicalExpr::getType() {
        return Type::boolType;
}

int EqualityExpr::getSpace() {
        const char* t = op->getTokenString();
        if (strcmp("==",t) == 0) {
                return getSpaceEqual();
        } else if (strcmp("!=",t) == 0) {
                return getSpaceNotEqual();
        }
        return 0;
}

int EqualityExpr::getSpaceEqual() {
        return CodeGenerator::VarSize + right->getSpace() + left->getSpace();
}

int EqualityExpr::getSpaceNotEqual() {
        return CodeGenerator::VarSize * 4 + right->getSpace() + left->getSpace();
}

Type *EqualityExpr::getType() {
        return Type::boolType;
}

Location *EqualityExpr::codeGen(CodeGenerator *gen) {
        const char* t = op->getTokenString();
        if (strcmp("==",t) == 0) {
                return codeGenEqual(gen);
        } else if (strcmp("!=",t) == 0) {
                return codeGenNotEqual(gen);
        }
        return 0;
}

Location *EqualityExpr::codeGenEqual(CodeGenerator *gen) {
        Location *lt = left->codeGen(gen);
        Location *rt = right->codeGen(gen);
        if ( left->getType()->IsEquivalentTo(Type::stringType)) {
                return gen->GenBuiltInCall(StringEqual, lt, rt);
        } else {
                return gen->GenBinaryOp("==",lt,rt);
        }
}

Location *EqualityExpr::codeGenNotEqual(CodeGenerator *gen) {
        const char* r0 = gen->NewLabel();
        const char* r1 = gen->NewLabel();
        Location *returnVal = gen->GenTempVar();
        Location *lt = left->codeGen(gen);
        Location *rt = right->codeGen(gen);
        Location *eq;
        if (left->getType()->IsEquivalentTo(Type::stringType)) {
                eq = gen->GenBuiltInCall(StringEqual,lt,rt);
        } else {
                eq = gen->GenBinaryOp("==",lt,rt);
        }
        gen->GenIfZ(eq,r1);
        gen->GenAssign(returnVal, gen->GenLoadConstant(0));
        gen->GenGoto(r0);
        gen->GenLabel(r1);
        gen->GenAssign(returnVal, gen->GenLoadConstant(0));
        gen->GenLabel(r0);
        return returnVal;
}

Type *RelationalExpr::getType() {
        return Type::boolType;
}

Location *RelationalExpr::codeGen(CodeGenerator *gen) {
        const char *t = op->getTokenString();
        if (strcmp("<",t) == 0) {
                return codeGenLess(gen,left,right);
        } else if (strcmp("<=",t) == 0) {
                return codeGenLessEqual(gen,left,right);
        } else if (strcmp(">",t) == 0) {
                return codeGenLess(gen,right,left);
        } else if (strcmp(">=",t) == 0) {
                return codeGenLessEqual(gen,right,left);
        }
        return NULL;
}

Location *RelationalExpr::codeGenLess(CodeGenerator *gen, Expr *l, Expr *r) {
        Location *lt = l->codeGen(gen);
        Location *rt = r->codeGen(gen);
        return gen->GenBinaryOp("<",lt,rt);
}

Location *RelationalExpr::codeGenLessEqual(CodeGenerator *gen, Expr *l, Expr *r) {
        Location *rt = r->codeGen(gen);
        Location *lt = l->codeGen(gen);
        Location *ls = gen->GenBinaryOp("<",lt,rt);
        Location *eq = gen->GenBinaryOp("==",lt,rt);
        return gen->GenBinaryOp("||",ls,eq);
}

int RelationalExpr::getSpace() {
        const char *t = op->getTokenString();
        if (strcmp("<",t) == 0) {
                return getSpaceLess(left,right);
        } else if (strcmp("<=",t) == 0) {
                return getSpaceLessEqual(left,right);
        } else if (strcmp(">",t) == 0) {
                return getSpaceLess(right,left);
        } else if (strcmp(">=",t) == 0) {
                return getSpaceLessEqual(right,left);
        }
        return 0;
        
}

int RelationalExpr::getSpaceLess(Expr *l, Expr *r) {
        return CodeGenerator::VarSize + r->getSpace() + l->getSpace();
}

int RelationalExpr::getSpaceLessEqual(Expr *l, Expr *r) {
        return CodeGenerator::VarSize * 3 + r->getSpace() + l->getSpace();
}

Type *ArithmeticExpr::getType() {
        return right->getType();
}

Location *ArithmeticExpr::codeGen(CodeGenerator *gen) {
        if ( left == NULL ) {
                return codeGenUnary(gen);
        } else {
                return codeGenBinary(gen);
        }
}

Location *ArithmeticExpr::codeGenUnary(CodeGenerator *gen) {
        Location *rt = right->codeGen(gen);
        Location *z = gen->GenLoadConstant(0);
        return gen->GenBinaryOp(op->getTokenString(),z,rt);
}

Location *ArithmeticExpr::codeGenBinary(CodeGenerator *gen) {
        Location *lt = left->codeGen(gen);
        Location *rt = right->codeGen(gen);
        return gen->GenBinaryOp(op->getTokenString(), lt, rt);
}

int ArithmeticExpr::getSpace() {
        if ( left == NULL ) {
                return getSpaceUnary();
        } else {
                return getSpaceBinary();
        }
}

int ArithmeticExpr::getSpaceUnary() {
        return CodeGenerator::VarSize * 2 + right->getSpace();
}

int ArithmeticExpr::getSpaceBinary() {
        return CodeGenerator::VarSize + left->getSpace() + right->getSpace();
}